#!/usr/bin/python2.7
# -*- coding: utf-8 -*-

import ConfigParser

from PyQt4 import QtGui, QtCore

import ddithreecodecategories as ddi31CC
import i18n as virgilI18N

from converter import converter

# Import UI components
from ui.virgilui_auto import Ui_virgilMain
from ui.languageSelectDialog_auto import Ui_selectLanguageWindow
from ui.csv2DdiConvertorWindow_auto import Ui_csv2DdiConvertorWindow as Ui_csv2ddi

import treeModels as TModels

VERSION = "0.0.1B"
REVISION = "$Revision: 34 $".replace("$","") #SVN Attribute that gets updated on each check-in (we remove the $ $'s to make it readable

class virgil(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_virgilMain()

        QtCore.QCoreApplication.setOrganizationName("Virgil DDI Classifications Suite");
        QtCore.QCoreApplication.setOrganizationDomain("code.google.com/p/virgil-ui/"); 
        QtCore.QCoreApplication.setApplicationName("Virgil-UI");

        # User preferences / settings
        self.settings           = QtCore.QSettings("Virgil DDI Classifications Suite", "Virgil-UI")
        self.defaultLanguage    = unicode(self.getPref('defaultLanguage','en'))  # flag for the user preferred langauge when displaying DDI
        self.recentItems        = self.getPref('recentItems',[])                 # flag for the user preferred langauge when displaying DDI

        # Run time settings
        self.saved              = True                  # Flag to determine if we have unsaved changes
        self.displayLanguage    = "en"                  # This is the langauge used for the whole UI / changing this not yet implemented
        self.treeLanguage       = self.defaultLanguage  # This is the langauge currently selected for the labels in treeClassification
        self.updateByDefault    = True                  # True if the user wants changes pushed to DDI when switching between codes / not yet implemented
        self.selectedCode       = None                  # Code value of the currently edited category
        self.selectedCategory   = None                  # The current category we are editing
        self.selectedLanguage   = "en-au"               # The language of the label/description values that we are editing - selected in QComboBox.editLanguage 
        self.ui.setupUi(self)
        
        self.updateModel(TModels.ddi3_1.DDITreeModel(ddi=None))
    # here we connect signals with our slots
#        QtCore.QObject.connect(self.ui.button_open,QtCore.SIGNAL("clicked()"), self.file_dialog)
#        self.ui.btnAddNewCode.clicked.connect(self.addEntry)
#        self.ui.btnAddNewCodeList.clicked.connect(self.newCodeList)

    # Attach methods to changes in the tree
        self.ui.treeClassification.expanded.connect(self.expand)
        self.ui.treeClassification.collapsed.connect(self.collapse)
        self.ui.treeClassification.clicked.connect(self.updateEditFields)

        self.ui.editLabel.textEdited.connect(self.updateTreeLabel)
        self.ui.editCodeValue.textEdited.connect(self.updateTreeCodeValue)

        self.ui.editLanguage.activated.connect(self.changeEditLang)

        #connect Menus to methods
        self.ui.actionOpenDDICodeList.triggered.connect(self.openFile)
        self.ui.actionSaveDDICodeList.triggered.connect(self.saveFile)
        self.ui.actionSaveAsDDICodeList.triggered.connect(self.saveAsFile_DDI31)

#        self.ui.actionAdd_Sibling_Code.triggered.connect(self.addSiblingCode)
        self.ui.actionAdd_Child_Code.triggered.connect(self.addChildCode)
        self.ui.actionAdd_New_CodeList.triggered.connect(self.addCodeList)

        self.ui.actionNew_Classification.triggered.connect(self.newClassificationBundle)
        self.ui.actionImportCSV.triggered.connect(self.importCSV)

        self.ui.actionSet_default_language.triggered.connect(self.changeDefaultLanguage)

        self.ui.actionVanityBox.triggered.connect(self.vanityBox)
        self.ui.actionAboutPyQt.triggered.connect(self.AboutPyQt)
        self.ui.actionViewRawDDI.triggered.connect(self.viewRawDDI)
        self.ui.actionRefreshModel.triggered.connect(self.refreshModel)
        self.ui.actionCustomDebugCommand.triggered.connect(self.CustomDebugCommand)

        self.ui.treeClassification.setContextMenuPolicy( QtCore.Qt.CustomContextMenu )
        self.ui.treeClassification.customContextMenuRequested.connect(self.on_context_menu)

        self.ui.changeLabelLanguage.activated.connect(self.changeClassifcationLanguage)
        # self.ui.changeLabelLanguage.currentIndexChanged.connect(self.changeClassifcationLanguage)

        self.ui.addCategoryLanguage.clicked.connect(self.addCategoryLanguage)

        self.ui.actionDelete.triggered.connect(self.deleteItem)

        self.unsupportedFeature(self.ui.dockDDIMetadata)
        self.unsupportedFeature(self.ui.dockConcepts)
        self.unsupportedFeature(self.ui.toolbarSearch)
        self.unsupportedFeature(self.ui.toolbarExport)
        self.unsupportedFeature(self.ui.toolbarTextFormatting)
        self.unsupportedFeature(self.ui.actionImport_DDI_File)
        self.unsupportedFeature(self.ui.menuExport)
        self.unsupportedFeature(self.ui.actionAdd_Sibling_Code)
        self.unsupportedFeature(self.ui.actionSettings)
        self.unsupportedFeature(self.ui.actionSet_display_language)
        self.unsupportedFeature(self.ui.actionRemove_Selected)
        self.unsupportedFeature(self.ui.menuRecent_Local_Repositories)
        self.unsupportedFeature(self.ui.toolbarDebug)

        self.setupToolbars()

        # Hide and kill the temporary object holder

    # This is a debug-only method, and will change quite frequently, depending on the current debug info needed
    def CustomDebugCommand(self):
        pass
        #QtGui.QMessageBox.information(self, 'Raw DDI', self.ddi.toString())
         

    # Gets a user preference
    def getPref(self,key,default=None):
        return self.settings.value(key,default).toPyObject()

    def setPref(self,key,value):
        return self.settings.setValue(key,value)

    def changeDefaultLanguage(self,lang=None):
        success = True
        if lang == False:
            lang,success = self.languagePicker("Select default language")
        
        if success:
            self.treeLanguage = lang
            self.setPref("defaultLanguage",lang)

    def setupToolbars(self):
        self.ui.toolbarSearch.addWidget(self.ui.textSearchToolbar)  # Move Search bar to the search toolbar

    def refreshModel(self):
        self.updateModel(self.treeModel.clone())
        
        
    def viewRawDDI(self):
        QtGui.QMessageBox.information(self, 'Raw DDI', self.ddi.toString())

    def addCategoryLanguage(self):
        lang, success = self.languagePicker()
        print self.selectedCategory()
        if success:
            if lang not in self.selectedCategory['labels']:
                self.selectedCategory['labels'][lang] = ""
            if lang not in self.selectedCategory['descriptions']:
                self.selectedCategory['descriptions'][lang] = ""
            self.pushChanges()                      # Push changes into the model
            self.updateLabelDescription(lang)       # update the label/desc fields to their correct blank values

            if lang not in self.treeModel.getLanguages():
                self.treeModel.addLanguage(lang)

                self.updateLanguageSelector()

            self.selectedLanguage = lang
            self.updateEditLanguages()
            i = self.ui.editLanguage.findData(lang) # Find the index of the new language
            self.changeEditLang(i)                  # Select the new language

            # clear text and refresh
        else:
            pass # If we already have the language defined, don't add it again!

    def addLanguage(self,lang):
        pass

    def languagePicker(self,title = "Enter Language", default = None):
        common = []
        for code,data in virgilI18N.popularcodes.items():
            common.append(u"%s - %s / %s"%(code,data['name'],data['native']))
        common.sort()

        names = [""] + common
        lang,success = QtGui.QInputDialog.getItem(self,
            title,
            """Enter a <a href='http://en.wikipedia.org/wiki/ISO_639 '>2 letter ISO 639 Language Code ID</a>,<br>or select a common country from the list.<br>
                <br>
                Language titles are guides only, if you wish to edit an exisiting language,<br>
                be sure to change the country code (the text between the square brackets),<br>
                as this is what is used to identify the langauge.<br>
                <br>
                This list of languages was selected from the <a href="en.wikipedia.org/wiki/Global_Internet_usage#Internet_users_by_language">Top 10 langauges used on the Internet</a>.<br>
                American English was added, due to the large number of native users within Information Technology.""",
            names,
            current = 0,
            editable = True,
            )
        if success:
            # The entered a language successfully, good for them.
            lang = lang[0:2]
            lang = unicode(lang)
        return (lang,success)

    def unsupportedFeature(self,item):
        item.setVisible(False) # Hides instantly
        item.deleteLater()     # Deletes after a small delay

    def changeClassifcationLanguage(self,index):
        self.treeLanguage = self.treeModel.getLanguages()[index]
        self.treeModel.setLanguageByIndex(index)
        
    def updateModel(self,model):
        self.treeModel = model
        self.treeModel.setLanguage(self.treeLanguage)
        self.ui.treeClassification.setModel(self.treeModel) 
        self.redrawTreeView()
        self.updateLanguageSelector()

    def flagIconFromISO639(self,code):
        icon = QtGui.QIcon()
        try:
            flagcode = virgilI18N.knowncodes[code.lower()]['flag']
            icon.addPixmap(QtGui.QPixmap(":/flags/flags/%s.png"%flagcode), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        except:
            icon.addPixmap(QtGui.QPixmap(":/flags/flags/united_nations.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) #Throw in a a default icon
        return icon

    def updateLanguageSelector(self):
        self.ui.changeLabelLanguage.clear()
        index = 0
        for (i,lang) in enumerate(self.treeModel.getLanguages()):
            if unicode(self.treeLanguage) == unicode(lang):
                index = i
            icon = self.flagIconFromISO639(lang)
            lang = virgilI18N.iso639CodeToString(lang)
            self.ui.changeLabelLanguage.addItem(icon,lang)
        self.ui.changeLabelLanguage.setCurrentIndex(index)
        self.changeClassifcationLanguage(index)

    def updateModelAsDDITree(self,ddi):
        self.updateModel(TModels.ddi3_1.DDITreeModel(ddi=ddi)) 

    def redrawTreeView(self):
        self.ui.treeClassification.resizeColumnToContents(0)
        self.ui.treeClassification.resizeColumnToContents(1)

    def importCSV(self):
        import converter_ui as CUI
        dialog = CUI.converter_ui(parent=self,ddi=self.ddi)
        dialog.show()

    def newClassificationBundle(self):
        import uuid
        self.eraseUI()
        self.filename = None
        tmpID = unicode(uuid.uuid4())
        newID = QtGui.QInputDialog.getText(self,"Input ID","ID for the new CodeList Bundle\nThe default is a randomly generated UUID", QtGui.QLineEdit.Normal,tmpID)
        if newID[1] == True:
            newID = unicode(newID[0])
            self.ddi = ddi31CC.ddi_CC_wrapper(id = newID)
            self.updateModel(TModels.ddi3_1.DDITreeModel(ddi=self.ddi))

    def on_context_menu(self, point):
        self.ui.menuCodeLists.exec_(self.ui.treeClassification.mapToGlobal(point) )

    def addEntry(self):
        pass

    def AboutPyQt(self):
        QtGui.QMessageBox.aboutQt(self)
    def vanityBox(self):
        vanityText = """<html>
<head>
<meta name="qrichtext" content="1" />
</head>
<body>
<p>
<h1>Virgil UI - DDI CodeList Editor v{version}</h1>
</p>
<p>
{revision}<br>Released under GPLv3 Licence<br>
Details available at: <a href="http://code.google.com/p/virgil-ui/">http://code.google.com/p/virgil-ui/<a>
</p>
<p>
Primary Developer: <a href="http:/about.me/legostormtroopr">Samuel Spencer</a>
</p>
</body>
</html>
""".format(version=VERSION,revision=REVISION)
        QtGui.QMessageBox.about(self,"About Virgil UI", vanityText )

    """
    If the label box gets updated change the tree if we are editing the code display language
    """
    def updateTreeLabel(self,string):
        value = unicode(self.ui.editLabel.text())
        index = self.ui.treeClassification.selectedIndexes()[0]   # There can only be one selected at anytime, so take the first (and only) in the list
        return self.treeModel.setLabel(index,self.selectedLanguage,value)

    """
    If the code value box gets updated change the tree 
    """
    def updateTreeCodeValue(self,string):
        value = unicode(self.ui.editCodeValue.text())
        index = self.ui.treeClassification.selectedIndexes()[0]   # There can only be one selected at anytime, so take the first (and only) in the list
        return self.treeModel.setCodeValue(index,value)

    def addCodeList(self):
        lang = self.selectedLanguage

        import uuid
        codescheme_id      = "CodeScheme_%s"%unicode(uuid.uuid4())
        categoryscheme_id  = "CategoryScheme_%s"%unicode(uuid.uuid4())
        labels             = { lang : "Untitled Classification"}
        descriptions       = { lang : "Untitled Classification"}
        self.treeModel.addCodeList(codescheme_id,categoryscheme_id,labels,descriptions) 
        self.redrawTreeView()

    def addChildCode(self):
        # Resolve all the columns selected to their ponters and get a list of objects selected (this should only be one)
        selected = {}
        for i in self.ui.treeClassification.selectedIndexes():
            selected[i.internalPointer()] = i

        lang = self.selectedLanguage
        
        import uuid
        if len(selected) == 1:
            x = { "code"               : "01",
              "code_id"            : "Code_%s"%unicode(uuid.uuid4()),
              "category_id"        : "Category_%s"%unicode(uuid.uuid4()),
              "labels"             : { lang : "---"},
              "descriptions"       : { lang : "---"}
            }
            i = selected.keys()[0]
            index = selected[i]
            self.treeModel.addCode(index,x) 

    def madeChange(self):
        self.saved = False

    #returns True if the file was successfully save, false otherwise
    def saveFile(self):
        self.pushChanges()

        if self.filename is not None:
            f = open(self.filename,"w")
            self.ddi.saveToFile(f)
            f.close()
        else:
            self.saveAsFile_DDI31()
    def saveAsFile_DDI31(self):
        self.pushChanges()

        file = QtGui.QFileDialog.getSaveFileName(self, 'Save File As', '.')
        f = open(file,"w")
        self.ddi.saveToFile(f)
        f.close()

    def newCodeList(self):
        print "Hello"

    def openFile(self):
    #trigger save question here
        canOpenFile = True
        if not self.saved:
            cancel,discard,save = (0,1,2)
            reply = QtGui.QMessageBox.question(self, 'Unsaved Changes', "Do you want to save the changes to this document before closing?\n\nIf you don't save, your changes will be lost.", QtGui.QMessageBox.Discard, QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Save)
            if reply == QtGui.QMessageBox.Cancel:
                # user hits cancel, don't open a new file
                canOpenFile = False 
            if reply == QtGui.QMessageBox.Save:
                # user hits save, save file and open a new file
                canOpenFile = self.saveFile()
            if reply == QtGui.QMessageBox.Discard:
                # user hits discard, just open a new file
                canOpenFile = True
        if canOpenFile:
            file = QtGui.QFileDialog.getOpenFileName(self, 'Open DDI File', '.')
            if file:
                self.openDDI31File(file)

    def openDDI31File(self,file):
        self.eraseUI()               
        self.filename = file
        self.ddi = ddi31CC.ddi_CC_wrapper(self.filename)
        self.updateModel(TModels.ddi3_1.DDITreeModel(ddi=self.ddi))

    def eraseUI(self):
        self.selectedCode = None
        self.ui.editCodeValue.clear()                
        self.ui.editLanguage.clear()                
        self.ui.editDescription.clear()
        self.ui.editLabel.clear()

    def collapse(self, index):
        self.treeModel.collapse(index)
        self.redrawTreeView()
    def expand(self, index):
        self.treeModel.expand(index)
        self.redrawTreeView()

    def updateSelectedCategoryText(self):
        newLabel = unicode(self.ui.editLabel.text())
        if not 'virgil_err:' in newLabel:
            self.selectedCategory['labels'][self.selectedLanguage] = newLabel
            #self.ui.treeClassification.selectedItems()[0].setLabel(lang=self.selectedLanguage,label=newLabel)

        newDesc  = unicode(self.ui.editDescription.toPlainText())
        if not 'virgil_err:' in newDesc:
            self.selectedCategory['descriptions'][self.selectedLanguage] = newDesc
        
    def pushChanges(self):
        if self.selectedCategory is not None:
            self.updateSelectedCategoryText()
            obj = {'code':self.selectedCode, 'value':unicode(self.ui.editCodeValue.text()), 'category':self.selectedCategory}
            self.ddi.updateCodeCategory(obj)

    def updateEditLanguages(self):
        self.ui.editLanguage.clear()
        langs = list(set(self.selectedCategory['labels'].keys()) | set(self.selectedCategory['descriptions'].keys())) # get a list of all unique languages for this category
        langs.sort()

        selectedLanguageIndex = -1
        if len(langs) > 0:
            if self.selectedLanguage not in langs:
                self.selectedLanguage = langs[0]
            selectedLanguageIndex = langs.index(self.selectedLanguage)
                
            for lang in langs:
                icon = self.flagIconFromISO639(lang)
                self.ui.editLanguage.addItem(icon,virgilI18N.iso639CodeToString(lang),lang)
        else:
            self.selectedLanguage = None
        self.ui.editLanguage.setCurrentIndex(selectedLanguageIndex)

    def updateEditFields(self,selected):
        if self.updateByDefault and self.selectedCode != None:
            self.pushChanges()
        code_id = self.treeModel.getCodeID(selected)
        if self.selectedCode != code_id:
            self.eraseUI()

        print selected.internalPointer().childItems

        self.selectedCode = code_id
        self.selectedCategory = None
        (self.selectedCategory,editableFields) = self.treeModel.getCategory(selected)
        

        self.ui.editCodeValue.setEnabled(editableFields['value'])
        if 'value' in editableFields and editableFields['value'] == True:
            self.ui.editCodeValue.setText(self.treeModel.getCodeValue(selected))

        self.updateEditLanguages()
        
        self.updateLabelDescription(self.selectedLanguage)

    def changeEditLang(self,index):
        if self.selectedCode != None and index != -1:
            if self.selectedLanguage != None:
                self.updateSelectedCategoryText()
            self.selectedLanguage = unicode(self.ui.editLanguage.itemData(index).toString()) # Unpack the iso code from the Combo
            self.updateLabelDescription(self.selectedLanguage)
        else:
         # we have no languages, so we need to gray out the label and desc so people don't write there
            self.editingEnabledIs(False)

    def editingEnabledIs(self,canEdit):
        if not canEdit:
            self.ui.editLabel.setText("")
        self.ui.editLabel.setEnabled(canEdit)
        self.ui.editDescription.setEnabled(canEdit)

    def updateLabelDescription(self,lang):
        self.ui.editDescription.clear()
        self.ui.editLabel.clear()
        
        self.editingEnabledIs(True)
        newLabel = "virgil_err: NO LABEL AVAILABLE FOR LANGUAGE '%s'"%lang
        
        if lang in self.selectedCategory['labels'].keys():
            newLabel = self.selectedCategory['labels'][lang]
        self.ui.editLabel.setText(newLabel)
        self.ui.editLabel.setCursorPosition(0)
        #:self.ui.treeClassification.selectedItems()[0].setLabel(lang=lang,label=newLabel)
        
        newDescription = "virgil_err: NO DESCRIPTION AVAILABLE FOR LANGUAGE '%s'"%lang
        if lang in self.selectedCategory['descriptions']:
            newDescription = self.selectedCategory['descriptions'][lang]
        self.ui.editDescription.insertHtml(newDescription)

    def deleteItem(self):
        
        selected = {}
        for i in self.ui.treeClassification.selectedIndexes():
            selected[i.internalPointer()] = i
        
        i = selected.keys()[0]
        index = selected[i]

        if len(selected) == 1:
            confirm = QtGui.QMessageBox.warning(self, 
            'Deleting Item', 
            "Warning: Deleting this item will delete all child Codes. This will not remove the connected labels and descriptions, tions or leave this available to connect with new codes.\nThis action CANNOT be undone. Do you want to delete this item and all it's children?",
             QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
    #        "Warning: Deleting this item will delete all child Codes. You can also delete the corresponding labels and descriptions or leave this available to connect with new codes"

            if confirm == QtGui.QMessageBox.Yes:
                self.treeModel.deleteItem(index)

